/**
 * 级联选择器工具函数
 */

import type { CascaderOption } from '../types/cascader'

/**
 * 将平铺数据转换为级联数据结构
 * @param flatData 平铺的数据数组
 * @param options 转换配置选项
 * @returns 级联数据结构
 */
export function flattenToCascader(
  flatData: any[],
  options: {
    valueKey?: string
    labelKey?: string
    parentKey?: string
    rootValue?: any
  } = {}
): CascaderOption[] {
  const { 
    valueKey = 'id', 
    labelKey = 'name', 
    parentKey = 'parentId', 
    rootValue = null 
  } = options
  
  const map = new Map<any, CascaderOption>()
  const roots: CascaderOption[] = []
  
  // 第一遍遍历，创建所有节点
  flatData.forEach(item => {
    map.set(item[valueKey], {
      name: String(item[valueKey]),
      nameCn: String(item[labelKey]),
      nameEn: String(item[labelKey]), // 如果没有英文名，使用中文名作为默认值
      children: []
    })
  })
  
  // 第二遍遍历，建立父子关系
  flatData.forEach(item => {
    const node = map.get(item[valueKey])!
    const parentId = item[parentKey]
    
    if (parentId === rootValue) {
      roots.push(node)
    } else {
      const parent = map.get(parentId)
      if (parent) {
        parent.children!.push(node)
      }
    }
  })
  
  // 清理空的children数组
  const cleanChildren = (nodes: CascaderOption[]) => {
    nodes.forEach(node => {
      if (node.children && node.children.length === 0) {
        delete node.children
      } else if (node.children) {
        cleanChildren(node.children)
      }
    })
  }
  
  cleanChildren(roots)
  return roots
}

/**
 * 根据值路径查找对应的选项对象数组
 * @param options 级联数据源
 * @param path 值路径数组
 * @returns 对应的选项对象数组
 */
export function findOptionsByPath(
  options: CascaderOption[],
  path: string[]
): CascaderOption[] {
  const result: CascaderOption[] = []
  let currentOptions = options
  
  for (const value of path) {
    const option = currentOptions.find(opt => opt.name === value)
    if (option) {
      result.push(option)
      currentOptions = option.children || []
    } else {
      break
    }
  }
  
  return result
}

/**
 * 获取所有叶子节点选项
 * @param options 级联数据源
 * @returns 叶子节点选项数组
 */
export function getLeafOptions(options: CascaderOption[]): CascaderOption[] {
  const leaves: CascaderOption[] = []
  
  const traverse = (nodes: CascaderOption[]) => {
    nodes.forEach(node => {
      if (!node.children || node.children.length === 0) {
        leaves.push(node)
      } else {
        traverse(node.children)
      }
    })
  }
  
  traverse(options)
  return leaves
}

/**
 * 根据标签路径查找对应的值路径
 * @param options 级联数据源
 * @param labelPath 标签路径数组
 * @returns 对应的值路径数组
 */
export function findValuesByLabelPath(
  options: CascaderOption[],
  labelPath: string[]
): string[] {
  const result: string[] = []
  let currentOptions = options
  
  for (const label of labelPath) {
    const option = currentOptions.find(opt => opt.nameCn === label)
    if (option) {
      result.push(option.name)
      currentOptions = option.children || []
    } else {
      break
    }
  }
  
  return result
}

/**
 * 获取指定层级的所有选项
 * @param options 级联数据源
 * @param level 目标层级（从0开始）
 * @returns 指定层级的选项数组
 */
export function getOptionsByLevel(
  options: CascaderOption[],
  level: number
): CascaderOption[] {
  if (level === 0) {
    return options
  }
  
  const result: CascaderOption[] = []
  const traverse = (nodes: CascaderOption[], currentLevel: number) => {
    if (currentLevel === level) {
      result.push(...nodes)
      return
    }
    
    nodes.forEach(node => {
      if (node.children && node.children.length > 0) {
        traverse(node.children, currentLevel + 1)
      }
    })
  }
  
  traverse(options, 0)
  return result
}

/**
 * 检查指定路径是否存在
 * @param options 级联数据源
 * @param path 值路径数组
 * @returns 路径是否存在
 */
export function isPathValid(
  options: CascaderOption[],
  path: string[]
): boolean {
  if (!path.length) return true
  
  let currentOptions = options
  
  for (const value of path) {
    const option = currentOptions.find(opt => opt.name === value)
    if (!option) {
      return false
    }
    currentOptions = option.children || []
  }
  
  return true
}

/**
 * 获取级联数据的最大深度
 * @param options 级联数据源
 * @returns 最大深度
 */
export function getMaxDepth(options: CascaderOption[]): number {
  if (!options.length) return 0
  
  let maxDepth = 1
  
  const traverse = (nodes: CascaderOption[], currentDepth: number) => {
    maxDepth = Math.max(maxDepth, currentDepth)
    
    nodes.forEach(node => {
      if (node.children && node.children.length > 0) {
        traverse(node.children, currentDepth + 1)
      }
    })
  }
  
  traverse(options, 1)
  return maxDepth
}

/**
 * 搜索包含指定关键字的选项
 * @param options 级联数据源
 * @param keyword 搜索关键字
 * @param searchInValue 是否在value中搜索
 * @returns 匹配的选项路径数组
 */
export function searchOptions(
  options: CascaderOption[],
  keyword: string,
  searchInValue: boolean = false
): Array<{ path: string[], options: CascaderOption[] }> {
  if (!keyword.trim()) return []
  
  const results: Array<{ path: string[], options: CascaderOption[] }> = []
  
  const traverse = (nodes: CascaderOption[], currentPath: string[], currentOptions: CascaderOption[]) => {
    nodes.forEach(node => {
      const matchInNameCn = node.nameCn.toLowerCase().includes(keyword.toLowerCase())
      const matchInNameEn = node.nameEn.toLowerCase().includes(keyword.toLowerCase())
      const matchInName = searchInValue && node.name.toLowerCase().includes(keyword.toLowerCase())
      
      if (matchInNameCn || matchInNameEn || matchInName) {
        results.push({
          path: [...currentPath, node.name],
          options: [...currentOptions, node]
        })
      }
      
      if (node.children && node.children.length > 0) {
        traverse(node.children, [...currentPath, node.name], [...currentOptions, node])
      }
    })
  }
  
  traverse(options, [], [])
  return results
}

/**
 * 过滤级联数据，只保留满足条件的分支
 * @param options 级联数据源
 * @param predicate 过滤条件函数
 * @returns 过滤后的级联数据
 */
export function filterOptions(
  options: CascaderOption[],
  predicate: (option: CascaderOption, path: string[]) => boolean
): CascaderOption[] {
  const filter = (nodes: CascaderOption[], currentPath: string[] = []): CascaderOption[] => {
    const filtered: CascaderOption[] = []
    
    nodes.forEach(node => {
      const nodePath = [...currentPath, node.value]
      const shouldInclude = predicate(node, nodePath)
      
      let filteredChildren: CascaderOption[] = []
      if (node.children && node.children.length > 0) {
        filteredChildren = filter(node.children, nodePath)
      }
      
      // 如果节点本身满足条件，或者有满足条件的子节点，则包含这个节点
      if (shouldInclude || filteredChildren.length > 0) {
        filtered.push({
          ...node,
          children: filteredChildren.length > 0 ? filteredChildren : undefined
        })
      }
    })
    
    return filtered
  }
  
  return filter(options)
}

/**
 * 将级联数据转换为扁平数组
 * @param options 级联数据源
 * @param includeParentPath 是否包含父级路径信息
 * @returns 扁平化的数据数组
 */
export function flattenCascaderOptions(
  options: CascaderOption[],
  includeParentPath: boolean = false
): Array<CascaderOption & { path?: string[], level?: number }> {
  const result: Array<CascaderOption & { path?: string[], level?: number }> = []
  
  const traverse = (nodes: CascaderOption[], currentPath: string[] = [], level: number = 0) => {
    nodes.forEach(node => {
      const nodePath = [...currentPath, node.name]
      const flatNode: CascaderOption & { path?: string[], level?: number } = {
        ...node
      }
      
      if (includeParentPath) {
        flatNode.path = nodePath
        flatNode.level = level
      }
      
      // 移除children属性以避免循环引用
      delete flatNode.children
      result.push(flatNode)
      
      if (node.children && node.children.length > 0) {
        traverse(node.children, nodePath, level + 1)
      }
    })
  }
  
  traverse(options)
  return result
}

/**
 * 验证级联数据格式是否正确
 * @param options 级联数据源
 * @returns 验证结果
 */
export function validateCascaderOptions(
  options: any[]
): { valid: boolean, errors: string[] } {
  const errors: string[] = []
  
  if (!Array.isArray(options)) {
    errors.push('Options must be an array')
    return { valid: false, errors }
  }
  
  const validateNode = (node: any, path: string = ''): void => {
    const currentPath = path ? `${path}.${node.name || 'unknown'}` : (node.name || 'unknown')
    
    if (typeof node !== 'object' || node === null) {
      errors.push(`Invalid node type at ${currentPath}: expected object`)
      return
    }
    
    if (!node.hasOwnProperty('name') || typeof node.name !== 'string') {
      errors.push(`Missing or invalid 'name' property at ${currentPath}: expected string`)
    }
    
    if (!node.hasOwnProperty('nameCn') || typeof node.nameCn !== 'string') {
      errors.push(`Missing or invalid 'nameCn' property at ${currentPath}: expected string`)
    }
    
    if (!node.hasOwnProperty('nameEn') || typeof node.nameEn !== 'string') {
      errors.push(`Missing or invalid 'nameEn' property at ${currentPath}: expected string`)
    }
    
    if (node.children !== undefined) {
      if (!Array.isArray(node.children)) {
        errors.push(`Invalid 'children' property at ${currentPath}: expected array`)
      } else {
        node.children.forEach((child: any) => validateNode(child, currentPath))
      }
    }
  }
  
  options.forEach(node => validateNode(node))
  
  return {
    valid: errors.length === 0,
    errors
  }
}
